feat(studio): i18n pipeline (next-intl) — en/zh catalogs + locale switcher [PR-A]#1401
Merged
Conversation
…tcher Wire next-intl 3.26.5 infrastructure for Next.js 16 App Router: request config (cookie-based locale, NEXT_LOCALE), NextIntlClientProvider in root layout, en/zh message catalogs (nav + common namespace), LocaleSwitcher component in the header, and t() conversions for Shell/Breadcrumb/NavGroup/ ProjectChip. Pages (runs, shows, etc.) keep hardcoded English strings; PR-B re-derives page conversions after this merges. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…her aria-label
Review round 1 findings:
- Two skip links rendered (layout.tsx + Shell.tsx, both hardcoded) while
common.skipToMain sat dead in the catalogs. Consolidated to the single
layout.tsx link (earliest tab stop) and wired it through
getTranslations("common"); removed Shell's duplicate.
- en.json announced the locale switch in Chinese (切換到中文) to English
screen-reader users, and in Traditional characters at that. Now
"Switch to Chinese" — aria-labels describe the action in the current
locale.
- Noted removal condition on the Next 16 turbopack alias workaround.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ohdearquant
added a commit
that referenced
this pull request
Jun 11, 2026
…v keys [PR-B] (#1402) * feat(studio): i18n page conversions — kanban/playfield/dashboard + nav keys - Add nav catalog keys for Kanban (en: "Kanban", zh: "看板") and Playfield (en: "Playfield", zh: "运行场") with corresponding ITEM_KEY entries in NavGroup.tsx, following the pattern from PR #1401. - Convert app/kanban/page.tsx: PageHeader title/subtitle, all six lane labels, and empty-state messages to kanban.* catalog keys. - Convert app/playfield/page.tsx: PageHeader title/subtitle, table headers, "All projects" filter button, and empty-state to playfield.* catalog keys. - Convert app/page.tsx (dashboard): PageHeader, all five MetricCard labels + hints, SectionHeader titles, RunsTable headers, Shows table headers, SystemHealthCard labels, inventory strip, and fetchError string to dashboard.* catalog keys. - Both en.json and zh.json updated with all new keys; zh entries match the professional/concise register of existing translations. - lib/copy.ts consumers (errors.loadRuns, empty.runs) deliberately left unconverted to avoid double-indirection per task constraints. - Verified: npm run lint (0 warnings), npm run typecheck (0 errors), npm run build (clean, both locales embedded, no missing-key warnings). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(studio): i18n completeness gaps — inventory/allTime/plurals/Unassigned Address four mixed-language gaps identified in review: - dashboard inventory strip: convert "playbooks", "agents", "runs total", "shows" to dashboard.inventory.* keys (en+zh); restructure inventory from flat string to nested object in both catalogs. - dashboard rangeLabel: convert hardcoded "all time" fallback to dashboard.metrics.allTime key (zh: "全部时间"). - kanban pluralization: replace bare string interpolation with next-intl ICU plural syntax for agent count (agentCount) and run badge (runCount/runningCount); zh uses non-pluralizing "# 个代理" / "# 个运行" per Chinese grammar conventions. - playfield Unassigned: translate display-only render sites in ProjectSection header and filter chip via playfield.unassigned key (zh: "未分配"); internal sentinel string and Map keys/sort comparisons remain "Unassigned" unchanged. Also convert "{runs.length} active" to playfield.groupActive ICU key (zh: "{count} 活跃"). Verified: npm run lint (0 warnings), npm run typecheck (0 errors), npm run build (clean, no missing-key warnings). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(studio): zh plural catalog — ICU plural wrapper for # placeholder, unify 智能体 register Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR-A of the #1263 split per the rewrite roadmap — pipeline only, no page conversions.
next-intl3.26.5 for Next.js 16 App Router:i18n/request.ts(cookie-based locale resolution,NEXT_LOCALE,enfallback),NextIntlClientProviderin root layout,next.config.mjsplugin + turbopackresolveAliasfor Next 16 compat.messages/en.json+messages/zh.jsoncatalogs covering nav and common namespaces only (34 leaf keys each).runs.*andshowDetail.*sections from the draft were pruned — those keys target page strings that are deferred to PR-B.LocaleSwitchercomponent mounted in the header (betweenProjectChipandThemeToggle); cookie-based persistence (1-year,SameSite=Lax), page reload on switch.Shell,Breadcrumb,NavGroup,ProjectChip) touseTranslations("nav")— this proves the pipeline end-to-end (server locale resolution →NextIntlClientProvider→ clientuseTranslations).runs/page.tsx,shows/[topic]/page.tsx, and all other pages keep hardcoded English strings. PR-B re-derives those conversions against today's pages after this merges.What was pruned from the draft catalogs and why
runs.*(51 keys)runs/page.tsx— deferred to PR-B; page not converted hereshowDetail.*(48 keys)shows/[topic]/page.tsx— same, deferred to PR-Bmetadata.*(2 keys)useTranslationscall; metadata stays static for nowcommon.copy.*,common.time.*,common.duration.*CopyButton,Timestamp,Durationcomponents — not converted in PR-AKept:
nav.*(45 keys) +common.skipToMain(1 key) — everything actually consumed by the components modified in this PR.Catalog counts
next-intl version
3.26.5— installed from^3.26.0range. Compatible withnext@16.2.6(peerDep allows^10.0.0 || ... || ^15.0.0; Next 16 satisfies this range). Theturbopack.resolveAliasinnext.config.mjsworks around next-intl's plugin writing toexperimental.turbo— produces a warning on build but does not block compilation.Verification results
Build:
npm run build— passed. All 18 routes compiled. Output:TypeScript:
npm run typecheck(tsc --noEmit) — clean, zero errors.Lint:
npm run lint— 0 errors, 1 pre-existing warning (react-hooks/exhaustive-depsinruns/page.tsxline 321, confirmed present on main before this PR).Pre-commit hooks:
studio-frontend-eslintandstudio-frontend-prettierboth passed on commit.Python suite: No
.pyfiles were modified in this PR.Remaining manual QA
The following cannot be verified from this environment (no browser):
中文/ENbutton in the header — verify page reloads and nav group/item labels render in Chinese.NEXT_LOCALEcookie persists and locale is preserved.runs/page.tsxandshows/[topic]/page.tsxdisplay unchanged English strings (no regression from PR-A).zh.Partially addresses #1225. Does not close #1263 (draft PR is kept open; PR-B will supersede it).
🤖 Generated with Claude Code